package cn.iocoder.yudao.module.scrm.strategy.strategyimpl;

import cn.iocoder.yudao.module.scrm.controller.admin.invoice.vo.InvoiceSaveReqVO;
import cn.iocoder.yudao.module.scrm.controller.admin.order.vo.OrderSaveReqVO;
import cn.iocoder.yudao.module.scrm.controller.admin.receivable.vo.ReceivableSaveReqVO;
import cn.iocoder.yudao.module.scrm.dal.dataobject.invoice.InvoiceDO;
import cn.iocoder.yudao.module.scrm.dal.dataobject.order.OrderDO;
import cn.iocoder.yudao.module.scrm.dal.dataobject.receivable.ReceivableDO;
import cn.iocoder.yudao.module.scrm.dal.dataobject.refund.RefundDO;
import cn.iocoder.yudao.module.scrm.dal.mysql.invoice.InvoiceMapper;
import cn.iocoder.yudao.module.scrm.dal.mysql.order.OrderMapper;
import cn.iocoder.yudao.module.scrm.dal.mysql.receivable.ReceivableMapper;
import cn.iocoder.yudao.module.scrm.dal.mysql.refund.RefundMapper;
import cn.iocoder.yudao.module.scrm.enums.ErrorCodeConstants;
import cn.iocoder.yudao.module.scrm.enums.common.CrmBizTypeEnum;
import cn.iocoder.yudao.module.scrm.strategy.CompareStrategy;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.function.Function;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;


import static cn.iocoder.yudao.module.scrm.enums.ErrorCodeConstants.COMPARE_ORDER_INVOICES_REFUND;
import static cn.iocoder.yudao.module.scrm.util.CompareUtil.getFieldValue;

/**
 * 实现了 CompareStrategy 接口，用于处理订单和发票金额比较的逻辑。
 * 在修改的时候判断订单下面是否有回款退款发票等数据
 * @Author LiZhiMin
 * @Date 2024/9/9 11:10
 */
@Component
public class OrderReceivableRefundInvoiceStrategyImpl implements CompareStrategy {
    @Resource
    private InvoiceMapper invoiceMapper;

    @Resource
    private ReceivableMapper receivableMapper;

    @Resource
    private RefundMapper refundMapper;

    @Resource
    private OrderMapper orderMapper;

    /**
     * 处理 {@link InvoiceSaveReqVO} 类型的数据。
     * <p>
     * 获取订单信息、计算主键字段的值和外表字段的值，判断订单下面是否有回款退款发票信息
     * </p>
     *
     * @param request             请求对象，必须是 {@link OrderSaveReqVO} 类型。
     * @param foreignKeyFieldName 外部业务类型字段名称，用于标识应收表中的字段。
     * @param majorKeyFieldName   主要业务类型字段名称，用于标识订单表中的字段。
     */
    @Override
    public void handle(Object request, String foreignKeyFieldName, String majorKeyFieldName, CrmBizTypeEnum crmBizTypeEnum) throws NoSuchFieldException, IllegalAccessException {
        if (request instanceof OrderSaveReqVO) {
            // 处理 OrderSaveReqVO 类型的数据
            processSaveReqVoByType(request, foreignKeyFieldName, majorKeyFieldName, crmBizTypeEnum);
        } else {
            throw exception(ErrorCodeConstants.COMPARE_STRATEGY_TYPE, request.getClass().getName());
        }
    }

    /**
     * 处理 OrderSaveReqVO 类型的数据，判断是否有关联的字表数据。
     *
     * @param objVo               请求对象，应为 OrderSaveReqVO 类型
     * @param foreignKeyFieldName 关联表的主要字段名
     * @param majorJeyFieldName   订单表主表的主要字段名
     */
    private void processSaveReqVoByType(Object objVo, String foreignKeyFieldName, String majorJeyFieldName, CrmBizTypeEnum crmBizTypeEnum) throws NoSuchFieldException, IllegalAccessException {

        OrderSaveReqVO vo = (OrderSaveReqVO) objVo;
        // 获取订单信息
        OrderDO orderDO = orderMapper.selectById(vo.getId());
        // 获取主表的字段-总金额
        BigDecimal newTotalMoney = getFieldValue(OrderSaveReqVO.class, vo, foreignKeyFieldName);
        //判断是否存在关联表数据-存在就抛异常提示删除
        if (hasRelevantData(Long.valueOf(orderDO.getId()),newTotalMoney, crmBizTypeEnum, orderDO.getOrderTotalMoney() )) {
            throw exception(COMPARE_ORDER_INVOICES_REFUND,orderDO.getSystemNumber());
        }
    }



    /**
     * 查询关联表的总数。
     *
     * @param orderId             订单 ID
     * @param newTotalMoney 新的金额
     * @param crmBizTypeEnum      业务类型枚举
     * @return 如果关联表中存在数据，则返回 true；否则返回 false。
     */
    private Boolean hasRelevantData(Long orderId, BigDecimal newTotalMoney, CrmBizTypeEnum crmBizTypeEnum,BigDecimal oldTotalMoney) {
        Boolean result=false;
        //新的金额与旧的总金额不相等
        if (oldTotalMoney.compareTo(newTotalMoney)!=0){
            // 定义一个函数来获取对应表的数据
            Function<Long, List<?>> fetchDataFunction;
            switch (crmBizTypeEnum) {
                case CRM_RECEIVABLE:
                    fetchDataFunction = id -> receivableMapper.selectList(ReceivableDO::getOrderId, id);
                    break;
                case CRM_REFUND:
                    fetchDataFunction = id -> refundMapper.selectList(RefundDO::getOrderId, id);
                    break;
                case CRM_INVOICE:
                    fetchDataFunction = id -> invoiceMapper.selectList(InvoiceDO::getOrderId, id);
                    break;
                default:
                    return result;
            }
            // 使用流来检查数据是否存在
            result = fetchDataFunction.apply(orderId).stream().findAny().isPresent();
        }
        return result;

    }
}
